<?php
/**************************************************************************************************
	$Id: admin.php,v 1.9 2002/11/15 06:25:46 bboy Exp $
	admin.php: Functional and useful example of a web-based DNS administration interface.

	Copyright (C) 2002  Don Moore <bboy@bboy.net>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at Your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

/**************************************************************************************************
	Part of this code has been modified for use without register_globals, to meet the
	latest PHP standard, by Thijs Hendriks <thijs@cee-kay.net> of Cee-Kay Internet B.V.
**************************************************************************************************/

/*
**  CONFIG OPTIONS
*/

$dbhost = "localhost";			/* Hostname where SQL server is located */
$dbuser = "username";			/* SQL username */
$dbpass = "password";			/* SQL password */
$dbname = "mydns";				/* mydns database name */

$use_pgsql = 0;					/* Use PostgreSQL instead of MySQL? */

$result_group_size = 0;			/* Number of RR results to show per page (0=Show all) */

/* Automatically update serial when RR's are updated? */
$auto_update_serial = 0;		/* 0=No, 1=YYYYMMDDHH, 2=Unix timestamp (recommended) */

$rrtablename = "rr";				/* Name of your RR table */
$soatablename = "soa";			/* Name of your SOA table */
$ptrtablename = "ptr";			/* Name of your PTR table */

$ttl_min = 300;					/* Minimum allowed TTL */
$refresh_min = 300;				/* Minimum allowed refresh */
$retry_min = 300;					/* Minimum allowed retry */
$expire_min = 86400;				/* Minimum allowed expire */

$default_ttl = 86400;			/* Default TTL for new zone */
$default_refresh = 28800;		/* Default refresh for new zone */
$default_retry = 7200;			/* Default retry for new zone */
$default_expire = 604800;		/* Default expire for new zone */
$default_minimum = 86400;		/* Default minimum TTL for new zone */


/* Nothing configurable below this line */   /* "YEAH RIGHT!" */

/* A few convenience functions */
function esc($str) {
	global $use_pgsql;
	return ($use_pgsql ? pg_escape_string($str) : mysql_escape_string($str));
}
function nf($n) { return number_format($n); }
function S($n) { return ($n == 1 ? "" : "s"); }


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SEND_IMG
	This sends the images, so that users don't have to install the graphics.
	The binary data you see here are the PNG images used by this script.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function send_img($imgname)
{
	if ($imgname == "mydns-logo.png")
		$imgdata = "89504e470d0a1a0a0000000d49484452000000c2000000240803000000ec22159c00000003734" .
			"24954080808dbe14fe000000042504c5445ffffeef5f2dfece5d0e2d9c1e3d9c2d9cdb3cfbfa3c6b395bc" .
			"a585b39977aa8d69a0805a9f7f5995724a916d438c653b835a2e82592c794d1e70400f6f3f0e663300d54" .
			"b47dd000000097048597300000af000000af00142ac349800000016744558744372656174696f6e205469" .
			"6d650030362f31322f3032046a524d0000002174455874536f667477617265004d6163726f6d656469612" .
			"046697265776f726b7320342e30ea2627750000036249444154789cd598eb96ab200c85818a824e8f0c1e" .
			"dfff554ff15693ec60d74cd73a33fb574bb8e48318a2c6fc1a59dfc65dadf74f43370aed26af9b2abac95" .
			"19bee319c1636d4f8019bbbadd185fb34734de3476cad315158e6761b3748d30b085e8e3aebbe7b659821" .
			"a0e6b802dcf5f93c4418b6c924f71b10e6397b8830dd3484be361b46c85b448001ef4098e71e21cc4941a" .
			"81c818a30affb812c9ec86e5ebb7363b8465819446b8408d5335011d6b912b064f26f0fdffa3e21b50861" .
			"dd3ae6098a85b31484e5482d1ad0c97e4acfba3244c85622809c42a420cc65aa0e190c3d06b720d09e7f2" .
			"ed65cd5218425c04843640bce39c612ac310ee31a251a42497c109fb91b401cbdf22c3c722b44280e91ff" .
			"91f54a3475343e3805e1b1004aa92523915d5967243dc71732d23a136a9d2c4360b34dad918208134ea96" .
			"5617a0c25925ad2e2d9a2614953ddc867f210e1b17955845db9dcf5b71ac22363e05c66d831041e7189df" .
			"0b7b49c1e3b2c50833dd90584d15b9ab20f430a52e08c4c5c4993a0d81fbc2a37cd7c47ac1783e34e808d" .
			"9e129cb0812138e465c16b7f351d8b150d21078af8ba43a088463ef7bf16391a820028db8eeed08eea287" .
			"48aa2223dea95d3893481c6559237d1701df4f270739826737c91c00027192c451ac20fca5ed1d4548f8d" .
			"92b13b6d5c76112083c113980408fe13c9dd51178766c28c2e8a0a34bb56603e6db3ce4080db5278310b4" .
			"db2b02e386603f69736657dbc8ae97f38c65b8eff6774e8ee33982e1b52842e071bdcbaa081d0fd028102" .
			"a3533155b5c22d048e2a7a444c5aa01d93ecb2bb0eceb2402da9807c218bbf3bbbe69d96e4804124989ef" .
			"8db213875b9528e3ae49042b1f077e5840e271a6976dd010909f43fd41392b891783e5db48233a5e23885" .
			"df6f4454f54b25a406e9d5f44981a03118cb896ae112240386d45a9801404e9e8a85ab856028420ca894b" .
			"84497c472acfcd3392828e208f41bb003402886059cabc4468858bc58f6724b90a02af5d9edf002f08faf" .
			"dbb071cdef04ab58ab0be014984239292b43f00f76f852c7df8d71006776c02446025511d61587743221c" .
			"9114108272ab3dbfb6aa0879ec5b6bcc0502bd98cabda09448a977e66b52109a2f4ef78a96ea827f5fb6d" .
			"7e33461045408fc584184743dee070921a46f9cea7f1040e87f170147c8f7f0d5c4f02efd0370b2736a96" .
			"7376a30000000049454e44ae426082";
	else if ($imgname == "helpHigh.png")
		$imgdata = "89504e470d0a1a0a0000000d4948445200000011000000110403000000c9435ac900000003734" .
			"24954080808dbe14fe00000002d504c5445ffffeef5f2dfece5d0e2d9c1d9ccb2cfbfa3c5b294bca585b2" .
			"99779f7f598c653b82592c794c1d6f3f0e663300c8518285000000097048597300000b1200000b1201d2d" .
			"d7efc00000016744558744372656174696f6e2054696d650030372f33312f3032ca68a577000000217445" .
			"5874536f667477617265004d6163726f6d656469612046697265776f726b7320342e30ea2627750000005" .
			"d49444154789c636040024c2e2e026086edbb77efde4e04b1fc80ac77afe1ac770670960390a5eae2fdee" .
			"dd1b8866b677ef5e40585cefde6d80b0f2201a181898efbd7b0e1162ce687180b0b8dfbd0d80b080062e4" .
			"01763507160400100607e2b3e2aa8aaa10000000049454e44ae426082";
	else if ($imgname == "ptrHigh.png")
		$imgdata = "89504e470d0a1a0a0000000d4948445200000038000000110803000000bffb9fd200000003734" .
			"24954080808dbe14fe000000033504c5445ffffeef5f2dfece5d0e2d9c1d9ccb2cfbfa3c5b294bca585b2" .
			"9977a98c689f7f5995724a8c653b82592c794c1d6f3f0e663300ae26c2a8000000097048597300000b120" .
			"0000b1201d2dd7efc00000016744558744372656174696f6e2054696d650030372f33312f3032ca68a577" .
			"0000002174455874536f667477617265004d6163726f6d656469612046697265776f726b7320342e30ea2" .
			"627750000009149444154789cc5924b0ec4200840b13a14ab53bdff69c749fd21b589abbe15481e2211e0" .
			"0dacef385069cf409e92aea28f8cb0f39ce2004ec4112146bd2486346639e1628a64f326fa54ffccc45c3" .
			"88cd96b64b626e2156e5c24a2b3bec174bdc751a7cbf9f79662e6b4e53e217ed5931814dc8ac15d8348d1" .
			"bbaeefb89cc68da8f206dcaa083a4f655745287f11e10d7ec57d1e398416f97f0000000049454e44ae426" .
			"082";
	else if ($imgname == "soaHigh.png")
		$imgdata = "89504e470d0a1a0a0000000d49484452000000390000001108030000005039f4ec00000003734" .
			"24954080808dbe14fe000000033504c5445ffffeef5f2dfece5d0e2d9c1d9ccb2cfbfa3c5b294bca585b2" .
			"9977a98c689f7f5995724a8c653b82592c794c1d6f3f0e663300ae26c2a8000000097048597300000b120" .
			"0000b1201d2dd7efc00000016744558744372656174696f6e2054696d650030372f33312f3032ca68a577" .
			"0000002174455874536f667477617265004d6163726f6d656469612046697265776f726b7320342e30ea2" .
			"62775000000ec49444154789cc5934bb6c420084431c16fd4b8ffd5361e103ffd666fd03512a4f48209c0" .
			"af64637e1ba9e41c7049d41c6eaef059754fdf5ddaa200807589f3d56b964c54a359ebbad36d717be9927" .
			"b89ab3aa5b006d243b8573b5400225fcfb1e206d9ef4e4b685eae72283b54ca58aeecb83b5c8287178eb6" .
			"122fbdc09ab0e39e7d0a134e9cc0b0cf685771afb43a6bfa723a3e3b22b61db73f0c225ab14a9fcfa4398" .
			"63d71e9c1bbe455eb986de5af8316f1702aee9e8d835185f54828ee962c0676eb6b652e893a924306eea0" .
			"eacd399e591c1f64f6463e836661be13ea84ae7ede0c47cafcf57bfc5b1fd647208775917c7a000000004" .
			"9454e44ae426082";
	else if ($imgname == "addHigh.png")
		$imgdata = "89504e470d0a1a0a0000000d49484452000000230000000b0803000000c2f8c43000000003734" .
			"24954080808dbe14fe000000033504c5445663300d9ccb295724affffee794c1dbca585e2d9c1b29977a9" .
			"8c68f5f2df82592ccfbfa3ece5d0c5b2948c653b9f7f596f3f0e9961e9d0000000097048597300000b120" .
			"0000b1201d2dd7efc0000002174455874536f667477617265004d6163726f6d656469612046697265776f" .
			"726b7320342e30ea26277500000016744558744372656174696f6e2054696d650030392f31332f30324a9" .
			"e45c10000008949444154789c85905912c42008445112895b92fb9f766818f4335d16d5e01354e26f1142" .
			"32551e6ed22aa5114c21d3c5421436dc519c39e1756d86b67bab314df72f4d0b766ed1949a8128520733d" .
			"43c5dc3094638450be6db0a6a262e80d09ce93e1a0cda4d3079cd7e6cd6f1772416873275217e1a6abb38" .
			"f12eb4ce3e3150a9f1f69ce20f3ff403f78203d075674c210000000049454e44ae426082";
	else if ($imgname == "helpLow.png")
		$imgdata = "89504e470d0a1a0a0000000d4948445200000011000000110403000000c9435ac900000003734" .
			"24954080808dbe14fe00000002d504c5445ffffeefffce9fff9e3fff5defff2d9ffefd3ffecceffe9c9ff" .
			"e5c3ffdfb9ffd9aeffd5a9ffd2a3ffcf9effcc9902e51049000000097048597300000b1200000b1201d2d" .
			"d7efc00000016744558744372656174696f6e2054696d650030372f33312f3032ca68a577000000217445" .
			"5874536f667477617265004d6163726f6d656469612046697265776f726b7320342e30ea2627750000005" .
			"d49444154789c636040024c2e2e026086edbb77efde4e04b1fc80ac77afe1ac770670960390a5eae2fdee" .
			"dd1b8866b677ef5e40585cefde6d80b0f2201a181898efbd7b0e1162ce687180b0b8dfbd0d80b080062e4" .
			"01763507160400100607e2b3e2aa8aaa10000000049454e44ae426082";
	else if ($imgname == "ptrLow.png")
		$imgdata = "89504e470d0a1a0a0000000d4948445200000038000000110803000000bffb9fd200000003734" .
			"24954080808dbe14fe000000033504c5445ffffeefffce9fff9e3fff5defff2d9ffefd3ffecceffe9c9ff" .
			"e5c3ffe2beffdfb9ffdcb3ffd9aeffd5a9ffd2a3ffcf9effcc9961afdb69000000097048597300000b120" .
			"0000b1201d2dd7efc00000016744558744372656174696f6e2054696d650030372f33312f3032ca68a577" .
			"0000002174455874536f667477617265004d6163726f6d656469612046697265776f726b7320342e30ea2" .
			"627750000009149444154789cc5924b0ec4200840b13a14ab53bdff69c749fd21b589abbe15481e2211e0" .
			"0dacef385069cf409e92aea28f8cb0f39ce2004ec4112146bd2486346639e1628a64f326fa54ffccc45c3" .
			"88cd96b64b626e2156e5c24a2b3bec174bdc751a7cbf9f79662e6b4e53e217ed5931814dc8ac15d8348d1" .
			"bbaeefb89cc68da8f206dcaa083a4f655745287f11e10d7ec57d1e398416f97f0000000049454e44ae426" .
			"082";
	else if ($imgname == "soaLow.png")
		$imgdata = "89504e470d0a1a0a0000000d49484452000000390000001108030000005039f4ec00000003734" .
			"24954080808dbe14fe000000033504c5445ffffeefffce9fff9e3fff5defff2d9ffefd3ffecceffe9c9ff" .
			"e5c3ffe2beffdfb9ffdcb3ffd9aeffd5a9ffd2a3ffcf9effcc9961afdb69000000097048597300000b120" .
			"0000b1201d2dd7efc00000016744558744372656174696f6e2054696d650030372f33312f3032ca68a577" .
			"0000002174455874536f667477617265004d6163726f6d656469612046697265776f726b7320342e30ea2" .
			"62775000000ec49444154789cc5934bb6c420084431c16fd4b8ffd5361e103ffd666fd03512a4f48209c0" .
			"af64637e1ba9e41c7049d41c6eaef059754fdf5ddaa200807589f3d56b964c54a359ebbad36d717be9927" .
			"b89ab3aa5b006d243b8573b5400225fcfb1e206d9ef4e4b685eae72283b54ca58aeecb83b5c8287178eb6" .
			"122fbdc09ab0e39e7d0a134e9cc0b0cf685771afb43a6bfa723a3e3b22b61db73f0c225ab14a9fcfa4398" .
			"63d71e9c1bbe455eb986de5af8316f1702aee9e8d835185f54828ee962c0676eb6b652e893a924306eea0" .
			"eacd399e591c1f64f6463e836661be13ea84ae7ede0c47cafcf57bfc5b1fd647208775917c7a000000004" .
			"9454e44ae426082";
	else if ($imgname == "addLow.png")
		$imgdata = "89504e470d0a1a0a0000000d49484452000000230000000b04030000000708293100000003734" .
			"24954080808dbe14fe000000024504c5445ffcc99ffe5c3fffce9ffd5a9ffefd3ffdcb3fff5deffecceff" .
			"ffeeffd9aeffe2befff9e3a3fdcdca000000097048597300000b1200000b1201d2dd7efc0000002174455" .
			"874536f667477617265004d6163726f6d656469612046697265776f726b7320342e30ea26277500000016" .
			"744558744372656174696f6e2054696d650030392f31332f30324a9e45c10000008c49444154789c5d8e2" .
			"10ec24014445f29d0a6980d0a8944f6081ca10a8dda5422911b4aca22b9c10a1290a886e331bf09a623de" .
			"262f7f36439c2610a3f77e3708b117bea67ae0ed842a08b45237bda52946cca43a2a968e474d4d96984b7" .
			"d7852383647bbbe93499d78914bed4d7514528dfd90ac98acb80a5cf827df1acf812b0b752d6b1b7118a7" .
			"4ed7ff006fd03341c3bfbd1b0000000049454e44ae426082";
	else return;

	if ($len = strlen($imgdata))
	{
		$data = pack("H" . $len, $imgdata);
		header("Content-Type: image/png");
		/* The Last-Modified: keeps the images from being reloaded every time */
		header("Last-Modified: " . date("D, i M Y H:i:s O", filectime($_SERVER['SCRIPT_FILENAME'])));
		header("Content-Length: " . strlen($data));
		echo $data;
		exit;
	}
}
/*--- send_img() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	OUTPUT_HELP
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function output_help()
{
	global $result_group_size;

?>
<CENTER><DIV class=help>
Enter a search query in the input box located at the upper left corner of this page to edit
DNS records.
<P>
<TABLE width="100%" class=help>
<TR>
<TD>
Acceptable forms of input include:
<P>
<UL>
<LI>
	<B>A fully qualified domain name (FQDN)</B><BR>
	<I>example:</I>&nbsp; &quot;<TT>webserver.example.com</TT>&quot;<BR>
	<BR>
	Display and edit all DNS data exactly matching the FQDN specified.
	<P>

<LI>
	<B>A zone name</B><BR>
	<I>example:</I>&nbsp; &quot;<TT>example.com</TT>&quot;<BR>
	<BR>
	Display and edit all DNS data for the specified zone, as well as the SOA record for that
	zone.
<?php
	if ($result_group_size > 0)
		echo "If there are more than ".number_format($result_group_size)." resource".
				" records for the zone, multiple pages will be displayed.<BR>";
?>
	<P>

<LI>
	<B>An IP address</B><BR>
	<I>example:</I>&nbsp; &quot;<TT>192.168.1.1</TT>&quot;<BR>
	<BR>
	Display and edit the PTR record for the specified IP address.
	<P>

<LI>
	<B>A partial IP address</B><BR>
	<I>example:</I>&nbsp; &quot;<TT>192.168.1</TT>&quot;<BR>
	<BR>
	Display and edit the PTR records for all addresses within that class C.
	<P>
</UL>
</TD>
<TD width="30%" valign=top>
<TABLE class=plain><TR>
<TD class=help_inset>
	<TABLE class=help2>

		<TR>
			<TD class=helplabel_l>
				<DIV class=center>
					<IMG src="?img=soaHigh.png" alt="SOA"><BR>
					<IMG src="?img=addLow.png" alt="SOA add">
				</DIV>
			</TD>
			<TD class=helplabel_r>
				Click &quot;SOA&quot; to load the SOA browser.
			</TD>
		</TR>

		<TR><TD class=helplabel_r>&nbsp;<!-- spacer --></TD></TR>

		<TR>
			<TD class=helplabel_l>
				<DIV class=center>
					<IMG src="?img=soaLow.png" alt="SOA"><BR>
					<IMG src="?img=addHigh.png" alt="SOA add">
				</DIV>
			</TD>
			<TD class=helplabel_r>
				Click &quot;add&quot; to create new SOA records.
			</TD>
		</TR>

		<TR><TD class=helplabel_r>&nbsp;<!-- spacer --></TD></TR>

		<TR>
			<TD class=helplabel_l>
				<IMG src="?img=ptrHigh.png" alt="PTR">
			</TD>
			<TD class=helplabel_r>
				Click &quot;PTR&quot; to load the PTR browser.
				You can also create new PTR records here.
			</TD>
		</TR>

		<TR><TD class=helplabel_r>&nbsp;<!-- spacer --></TD></TR>

		<TR>
			<TD class=helplabel_l>
				<IMG src="?img=helpHigh.png" alt="Help">
			</TD>
			<TD class=helplabel_r>
				Click &quot;?&quot; to display this help page.
			</TD>
		</TR>

	</TABLE>
</TD>
</TR></TABLE>
</TD>
</TR>
</TABLE>

Your mouse pointer can be hovered over almost any item on the screen for context-sensitive
help, if your browser supports this functionality.

</DIV></CENTER>
<?php
}
/*--- output_help() -----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	OPEN_PAGE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function open_page($title = "MyDNS")
{
	global $query, $action;
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML lang="en">
<HEAD>
	<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
	<TITLE><?php echo $title; ?><?php if (strlen($query)) echo ": $query"; ?></TITLE>
	<SCRIPT language="JavaScript">
	<!--
		function imgSwap(name, type)  
		{
			eval("document." + name + ".src = '?img=" + name + type + ".png'");
		}
	-->
	</SCRIPT>
	<STYLE type="text/css">
	<!--
		A { color: blue; text-decoration: none; }
		A:hover { color: red; text-decoration: underline; }

		/* TD { border: green dotted 1px; } */  /* (for debugging tables) */

		BODY {
			background: #FFFFEE;
			color: #663300;
			margin: 1% 3% 3% 3%;
		}

		TABLE {
			background: #FFFFCC;
			padding: 10px;
			font-family: monospace;
		}

		TABLE.plain {
			background: #FFFFEE;
			padding: 0px;
		}

		TABLE.help {
			font-family: sans-serif;
		}

		TD.help_inset {
			background: #FFFFEE;
			border: #663300 solid 1px;
			font-family: sans-serif;
			text-align: center;
			padding: 5px;
			vertical-align: top;
		}

		TABLE.help2 {
			background: #FFFFEE;
			font-family: sans-serif;
		}

		TD.helplabel_l {
			border-right: #663300 solid 1px;
			padding: 5px 5px 0px 0px;
			vertical-align: top;
			text-align: center;
		}
		TD.helplabel_r {
			padding: 0px 0px 0px 5px;
			vertical-align: middle;
			text-align: left;
		}

		TD.textbox {
			padding-left: 0px;
			/* padding-right: 20px; */
		}

		TD.button {
			padding-left: 20px;
			text-align: center;
		}

		DIV.help {
			background: #FFFFCC;
			padding: 1em;
			font-family: sans-serif;
			width: 75%;
			margin-top: 3em;
			border: #663300 solid 1px;
			text-align: left;
		}

		TABLE.header {
			width: 100%;
			background: #FFFFEE;
			border-bottom: #663300 solid 2px;
			padding-bottom: 2px;
			font-family: sans-serif;
			font-size: 75%;
			vertical-align: middle;
		}

		TABLE.rr {
			width: 100%;
		}

		TABLE.notice {
			padding: 10px;
			font-family: sans-serif;
			font-weight: bold;
			text-align: center;
		}

		H1 {
			font-family: sans-serif;
			font-weight: bold;
			font-size: 300%;
		}

		CAPTION {
			background: #FFFFCC;
			padding: 6px;
			border-bottom: #663300 solid 1px;
			font-family: sans-serif;
			font-size: 150%;
			font-weight: bold;
			text-align: left;
		}

		TD {
			padding: 3px 5px 3px 5px;
		}

		TD.leftindent {
			padding: 3px 10px 3px 100px;
		}

		TD.rrinsert {
			padding-top: 20px;
		}

		TD.offsetbox {
			padding-bottom: 20px;
		}

		TABLE.offset {
			font-size: 70%;
			color: #999999;
			border-bottom: #663300 solid 1px;
			padding: 0px;
		}

		TD.centeroffset {
			color: #663300;
		}

		TT {
			font-weight: bold;
		}
	-->
	</STYLE>
</HEAD>
<BODY>
<!-- Page header -->
<FORM action="<?php echo $_SERVER['PHP_SELF']; ?>" method=GET>
<TABLE class=header>
	<TR>
		<TD align=left>
			<TABLE class=plain>
				<TR>
					<TD class=textbox>
						<INPUT type=TEXT name=query value="<?php echo $query; ?>" size=25 maxlength=255
						 title="input zone or FQDN to edit records">
					</TD>
<?php
echo "<TD class=button>";
echo "<A href=\"?action=soa_browser\" onMouseOver=\"imgSwap('soa','High')\" onMouseOut=\"imgSwap('soa','Low')\">";
echo "<IMG name=\"soa\" src=\"?img=soaLow.png\" alt=\"SOA browser\" title=\"SOA browser\" border=0>";
echo "</A><BR>";
echo "<A href=\"?action=soa_add\" onMouseOver=\"imgSwap('add','High')\" onMouseOut=\"imgSwap('add','Low')\">";
echo "<IMG name=\"add\" src=\"?img=addLow.png\" alt=\"Add new SOA\" title=\"Add new SOA\" border=0>";
echo "</A>";
echo "</TD>\n";

echo "<TD class=button>";
echo "<A href=\"?action=ptr_browser\" onMouseOver=\"imgSwap('ptr','High')\" onMouseOut=\"imgSwap('ptr','Low')\">";
echo "<IMG name=\"ptr\" src=\"?img=ptrLow.png\" alt=\"PTR browser\" title=\"PTR browser\" border=0>";
echo "</A>";
echo "</TD>\n";

echo "<TD class=button>";
echo "<A href=\"?\" onMouseOver=\"imgSwap('help','High')\" onMouseOut=\"imgSwap('help','Low')\">";
echo "<IMG name=\"help\" src=\"?img=helpLow.png\" alt=\"Help\" title=\"Help\" border=0>";
echo "</A>";
echo "</TD>\n";
?>
				</TR>
			</TABLE>
		</TD>
		<TD align=right>
			<A href="http://mydns.bboy.net/">
				<IMG src="<?php echo $_SERVER['PHP_SELF']; ?>?img=mydns-logo.png"
					alt="MyDNS" title="http://mydns.bboy.net/" border=0></A>
		</TD>
	</TR>
</TABLE>
</FORM>
<?php
}
/*--- open_page() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CLOSE_PAGE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function close_page()
{
?>
</BODY>
</HTML>
<?php
}
/*--- close_page() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	OPEN_TABLE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function open_table($class = NULL, $caption = NULL, $width = "")
{
	echo "<P>\n";
	echo "<TABLE align=center" .
			($class ? " class=$class" : "") .
			(strlen($width) ? " width='$width'" : "") .
			">\n";
	if ($caption)
		echo "<CAPTION>$caption</CAPTION>";
}
/*--- open_table() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CLOSE_TABLE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function close_table()
{
	echo "</TABLE>\n";
	echo "</P>\n";
}
/*--- close_table() -----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	NOTICE
	Output an important message in a conspicuous box.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function notice($msg)
{
?>
<P>
	<TABLE class=notice align=center>
		<TR>
			<TD><?php echo $msg; ?></TD>
		</TR>
	</TABLE>
</P>
<?php
	return (-1);
}
/*--- notice() ----------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_ERROR
	Returns a string describing the most recent SQL error.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function sql_error()
{
	global $use_pgsql;
	return ($use_pgsql ? pg_last_error() : mysql_error());
}
/*--- sql_error() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	FATAL
	Output fatal error and exit.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function fatal($msg)
{
	notice($msg);
	close_page();
	exit;
}
function fatalSQL($msg)
{
	fatal($msg . "<BR><DIV class=main>" . sql_error() . "</DIV>");
}
/*--- fatal() -----------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_QUERY
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function sql_query($query)
{
	global $use_pgsql;

	return ($use_pgsql ? pg_exec($query) : mysql_query($query));
}
/*--- sql_query() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_FETCH_ROW
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function sql_fetch_row($result)
{
	global $use_pgsql;

	return ($use_pgsql ? pg_fetch_row($result) : mysql_fetch_row($result));
}
/*--- sql_fetch_row() ---------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_FETCH_ARRAY
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function sql_fetch_array($result)
{
	global $use_pgsql;

	return ($use_pgsql ? pg_fetch_array($result) : mysql_fetch_array($result));
}
/*--- sql_fetch_array() -------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_NUM_ROWS
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function sql_num_rows($result)
{
	global $use_pgsql;

	return ($use_pgsql ? pg_num_rows($result) : mysql_num_rows($result));
}
/*--- sql_num_rows() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_COUNT
	Simple wrapper to return a numeric value from a query whose result contains only one row and
	column.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function sql_count($query, $what)
{
	global $use_pgsql;

	$res = sql_query($query) or fatalSQL("Error counting $what.");
	$row = sql_fetch_row($res);
	return ($row[0]);
}
/*--- sql_count() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	FIXFQDN
	Trims the specified name, makes sure it has a dot at the end.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function fixfqdn($name)
{
	$name = trim($name);
	$len = strlen($name);
	if ($len && $name[($len-1)] != '.')
		$name .= ".";
	return ($name);
}
/*--- fixfqdn() ---------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	DURATION
	Output the human-friendly duration of time represented by a specified number of seconds.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function duration($seconds)
{
	$weeks = floor($seconds / 604800); $seconds -= ($weeks * 604800);
	$days = floor($seconds / 86400); $seconds -= ($days * 86400);
	$hours = floor($seconds / 3600); $seconds -= ($hours * 3600);
	$minutes = floor($seconds / 60); $seconds -= ($minutes * 60);
	if ($weeks) $rv .= "$weeks" . " week" . S($weeks);
	if ($days) $rv .= (strlen($rv) ? ", " : "") . "$days" . " day" . S($days);
	if ($hours) $rv .= (strlen($rv) ? ", " : "") . "$hours" . " hour" . S($hours);
	if ($minutes) $rv .= (strlen($rv) ? ", " : "") . "$minutes" . " minute" . S($minutes);
	if ($seconds || !strlen($rv))
		$rv .= (strlen($rv) ? ", " : "") . "$seconds" . " second" . S($seconds);
	return ($rv);
}
/*--- duration() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SERIAL_GUESS
	Attempt to guess a good value for incrementing serial number.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function serial_guess($serial)
{
	$now = time();
	$low = $now - (31449600 * 2);							/* Time 2 years ago */
	$high = $now + (31449600 * 1);						/* Time 1 year hence */
	$curyear = (int)strftime("%Y", $now);				/* The current year */
	$timestamp = strftime("%Y%m%d", $now);				/* The current timestamp */

	/* If the first four characters look like a year, suggest a YYYYMMDD type format */
	$first = substr($serial, 0, 4);
	if ($first >= ($curyear-10) && $first <= ($curyear+1))
	{
		$rv = substr($timestamp, 0, strlen($serial));
		return ("current " . substr("YYYYMMDD", 0, strlen($serial)) . " is $rv");
	}

	/* If it looks like a Unix timestamp, return the current timestamp */
	if ($serial >= $low && $serial <= $high)
	{
		if ($now == $serial) $now++;
		return ("current Unix timestamp is $now");
	}

	/* If the current serial is a number that's less than the unix time 10 years ago, assume
		the serial is a simple number being incremented */
	if ($serial < $low)
		return ("suggested update value: " . ($serial+1));

	/* Otherwise return the "timestamp of choice" - YYYYMMDD */
	return ("current YYYYMMDD is $timestamp");
}
/*--- serial_guess() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	LOAD_SOA
	Attempts to load a SOA record for the specified query.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function load_soa($fqdn)
{
	global $soa_use_active, $soatablename;
	global $host;		/* Any extraneous hostname found prior to the origin */

	$fqdn = fixfqdn($fqdn);
	for ($n = 0; $n < strlen($fqdn); $n++)
		if ($n == 0 || $fqdn[$n] == '.')
		{
			$part = substr($fqdn, ($n == 0 ? $n : ($n + 1)));
			if (strlen($part))
			{
				if ($soa_use_active)
					$fields = "*,active+0 AS active_num";
				else
					$fields = "*";
				$res = sql_query("SELECT $fields FROM $soatablename WHERE origin='".esc($part)."'")
					or fatalSQL("Error locating SOA for &quot;$part&quot;.");
				if ($soa = sql_fetch_array($res))
				{
					if (strlen($part) != strlen($fqdn))
					{
						$host = substr($fqdn, 0, strlen($fqdn) - strlen($part));
						if ($host[strlen($host)-1] == '.')
							$host = substr($host, 0, strlen($host)-1);
					}
					return ($soa);
				}
			}
		}
	return 0;
}
/*--- load_soa() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SOA_FORM
	Outputs the "edit soa" form.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function soa_form($soa, $new = 0)
{
	global $query, $soa_use_active, $soa_use_xfer;

?>
<FORM method=POST action="<?php echo $_SERVER['PHP_SELF']; ?>">
<?php
	if ($new)
		echo "<INPUT type=hidden name=action value=\"soa_add\">\n";
	else
		echo "<INPUT type=hidden name=action value=\"soaupdate\">\n";
?>
<INPUT type=hidden name=query value="<?php echo $query; ?>">
<INPUT type=hidden name=soa value="<?php echo $soa[id]; ?>">
<TABLE align=center class=soa>
	<TR>
		<TD colspan=3>
			<TABLE><TR>
<?php
	if ($soa_use_active)
	{
		if ($soa[active_num] == 1)
			$checked = " checked";
?>
<TD><INPUT type=checkbox name=active value="Y" title="Entire zone active/inactive"<?php echo $checked; ?>></TD>
<?php
	}
?>

				<TD>
<?php
	if ($new)
		echo "<INPUT type=text name=origin value=\"$soa[origin]\" size=25".
			  " title=\"The origin for this zone.\">\n";
	else
		echo "<SPAN title=\"zone id $soa[id]\"><B>$soa[origin]</B></SPAN>\n";
?>
				</TD>
				<TD>
					<INPUT type=text name=ttl value="<?php echo $soa[ttl]; ?>" size=7
					 title="The TTL for this SOA record.">
				</TD>
				<TD nowrap>IN SOA</TD>
				<TD>
					<INPUT type=text name=ns value="<?php echo $soa[ns]; ?>" size=30 maxlength=255
					 title="The authoritative nameserver for this zone.">
				</TD>
				<TD nowrap>
					<INPUT type=text name=mbox value="<?php echo $soa[mbox]; ?>" size=30 maxlength=255
					 title="The administrative mailbox for this zone."> (
				</TD>
			</TR></TABLE>
		</TD>
	</TR>
	<TR>
		<TD class=leftindent>
			<INPUT type=text name=serial value="<?php echo $soa[serial]; ?>" size=15
			 title="The serial number for this zone.">
		</TD>
		<TD colspan=2>; Serial (<?php echo serial_guess($soa[serial]); ?>)</TD>
	</TR>
	<TR>
		<TD class=leftindent>
			<INPUT type=text name=refresh value="<?php echo $soa[refresh]; ?>" size=7
			 title="SOA refresh time, in seconds.">
		</TD>
		<TD colspan=2>; Refresh (currently <?php echo duration($soa[refresh]); ?>)</TD>
	</TR>
	<TR>
		<TD class=leftindent>
			<INPUT type=text name=retry value="<?php echo $soa[retry]; ?>" size=7
			 title="SOA retry time, in seconds.">
		</TD>
		<TD colspan=2>; Retry (currently <?php echo duration($soa[retry]); ?>)</TD>
	</TR>
	<TR>
		<TD class=leftindent>
			<INPUT type=text name=expire value="<?php echo $soa[expire]; ?>" size=7
			 title="SOA expire time, in seconds.">
		</TD>
		<TD colspan=2>; Expire (currently <?php echo duration($soa[expire]); ?>)</TD>
	</TR>
	<TR>
		<TD class=leftindent>
			<INPUT type=text name=minimum value="<?php echo $soa[minimum]; ?>" size=7
			 title="Minimum TTL for records within zone, in seconds.">
			)
		</TD>
		<TD>; Minimum TTL for zone (currently <?php echo duration($soa[minimum]); ?>)</TD>
<?php
	if ($soa_use_xfer)
	{
?>
	</TR>
	<TR>
		<TD class=leftindent colspan=2>
			Allow zone transfer from
			<INPUT type=text name=xfer value="<?php echo $soa[xfer]; ?>" size=30
			 title="Comma-separated list of IP addresses allowed to perform zone transfers.  Wildcards are OK.">
		</TD>
<?php
	}
	if ($new)
		echo "<TD align=right><INPUT type=submit name=\"soaaction\" value=\"Create new SOA\"></TD>\n";
	else
	{
?>
		<TD align=right><INPUT type=submit name="soaaction" value="Update"></TD>
		<TD align=right><INPUT type=submit name="soaaction" value="Delete"></TD>
<?php
	}
?>
	</TR>
</TABLE>
</FORM>
<?php
}
/*--- soa_form() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RRFORM
	Outputs the one-row "form" for a resource record.
	If $rr is not-NULL, output a form with Update and Delete buttons.
	If $rr is NULL, output a form with empty fields and an "add" button.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function rrform($soa, $rr = NULL, $force_name = NULL)
{
	global $query, $rr_use_active;

	$action = ($rr ? "rrupdate" : "rrinsert");

?>
<FORM method=POST action="<?php echo $_SERVER['PHP_SELF']; ?>">
<INPUT type=hidden name=query value="<?php echo $query; ?>">
<INPUT type=hidden name=action value="<?php echo $action; ?>">
<INPUT type=hidden name=soa value="<?php echo $soa[id]; ?>">
<INPUT type=hidden name=rr value="<?php echo $rr[id]; ?>">
	<TR>
<?php
	if ($rr_use_active)
	{
		echo "<TD class=$action>";
		if ($rr)
		{
			if ($rr[active_num] == 1)
				$checked = " checked";
			echo "<INPUT type=checkbox name=active value=\"Y\" title=\"This record active/inactive\"$checked>";
		}
		echo "</TD>";
	}
?>
		<TD class="<?php echo $action; ?>">
<?php
	if ($rr)
	{
		echo "<SPAN title=\"rr $rr[id] \nzone $rr[zone]\">";
		echo (strlen($rr[name]) ? $rr[name] : "<B>$soa[origin]</B>");
		echo "</SPAN>";
		echo "<INPUT type=hidden name=name value=\"$rr[name]\">";
	}
	else if ($force_name)
	{
		echo $force_name;
		echo "<INPUT type=hidden name=name value=\"$rr[name]\">";
	}
	else
		echo "<INPUT type=text name=name size=30 title=\"The name for this resource record.\">";
?>
		</TD>
		<TD class="<?php echo $action; ?>">
			<INPUT type=text name=ttl value="<?php echo ($rr ? $rr[ttl] : $soa[minimum]); ?>" size=7
			 title="The TTL for this resource record.">
		</TD>
		<TD class="<?php echo $action; ?>">IN</TD>
		<TD class="<?php echo $action; ?>">
<?php
	echo "<SELECT name=type size=1>";
	foreach (array("A","AAAA","CNAME","MX","NS","TXT") as $type)
		echo "<OPTION" . (!strcasecmp($rr[type], $type) ? " selected" : "") . ">$type";
	echo "</SELECT>";
?>
		</TD>
		<TD class="<?php echo $action; ?>">
			<INPUT type=text name=aux value="<?php echo ($rr[aux] ? $rr[aux] : ""); ?>" size=3
			 title="Auxillary value for this resource record.">
		</TD>
		<TD class="<?php echo $action; ?>">
			<INPUT type=text name=data value="<?php echo $rr[data]; ?>" size=30 maxlength=255
			 title="Data for this resource record.">
		</TD>
<?php
	if ($rr)				/* Output "Update" and "Delete" buttons */
	{
?>
		<TD class="<?php echo $action; ?>"><INPUT type=submit name="rraction" value="Update"></TD>
		<TD class="<?php echo $action; ?>"><INPUT type=submit name="rraction" value="Delete"></TD>
<?php
	}
	else					/* $rr is NULL; output a "Create" button */
	{
?>
		<TD class="<?php echo $action; ?>" colspan=2><INPUT type=submit value="Create new RR"></TD>
<?php
	}
?>
	</TR>
</FORM>
<?php
}
/*--- rrform() ----------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	PTRFORM
	Outputs the one-row "form" for a PTR record.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function ptrform($ptr = NULL)
{
	global $query, $ptr_use_active;

	$action = ($ptr ? "ptrupdate" : "ptrinsert");

	if ($ptr)
		$ptr[dd] = long2ip($ptr[ip]);

?>
<FORM method=POST action="<?php echo $_SERVER['PHP_SELF']; ?>">
<INPUT type=hidden name=query value="<?php echo $query; ?>">
<INPUT type=hidden name=action value="<?php echo $action; ?>">
<INPUT type=hidden name=ptr value="<?php echo $ptr[id]; ?>">
	<TR>
		<TD class="<?php echo $action; ?>">
<?php
	if ($ptr && $ptr_use_active)
	{
		if ($ptr[active_num] == 1)
			$checked = " checked";
		echo "<INPUT type=checkbox name=active value=\"Y\" title=\"This record active/inactive\"$checked>";
	}
?>
		</TD>
		<TD class="<?php echo $action; ?>">
<?php
	if ($ptr)
	{
		echo "<SPAN title=\"ptr $ptr[id]\">$ptr[dd]</SPAN>";
		echo "<INPUT type=hidden name=dd value=\"$ptr[dd]\">";
	}
	else
		echo "<INPUT type=text name=dd size=16 value=\"$query.\" title=\"The IP address.\">";
?>
		</TD>
		<TD class="<?php echo $action; ?>">IN PTR</TD>
		<TD class="<?php echo $action; ?>">
			<INPUT type=text name=name value="<?php echo $ptr[name]; ?>" size=30 maxlength=255
			 title="Name associated with this address.">
		</TD>
<?php
	if ($ptr)				/* Output "Update" and "Delete" buttons */
	{
?>
		<TD class="<?php echo $action; ?>"><INPUT type=submit name="ptraction" value="Update"></TD>
		<TD class="<?php echo $action; ?>"><INPUT type=submit name="ptraction" value="Delete"></TD>
<?php
	}
	else					/* $ptr is NULL; output a "Create" button */
	{
?>
		<TD class="<?php echo $action; ?>" colspan=2><INPUT type=submit value="Create new PTR"></TD>
<?php
	}
?>
	</TR>
</FORM>
<?php
}
/*--- ptrform() ---------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	OUTPUT_OFFSET_SELECT
	For large result sets, outputs a menu for navigating within the result.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function output_offset_select($offset, $total, $xtra = "")
{
	global $result_group_size, $query, $rr_use_active;

	if ($result_group_size == 0 || $total <= $result_group_size)
		return;

	if (!strlen($xtra))
		$xtra = "query=$query";

	/* Construct LEFT link buttons */
	for ($ct = 0, $cur = $offset - $result_group_size; $ct < 4; $ct++)
	{
		$txt = str_repeat("&lt;", ($ct + 1));
		if ($cur >= 0)
			$l[$ct] = "<A href=\"?$xtra&offset=$cur\" title=\"Back ".($offset-$cur)." records\">$txt</A>";
		else if (!$ct && $offset > 0 && $offset < $result_group_size)
			$l[$ct] = "<A href=\"?$xtra&offset=0\" title=\"Back ".($offset)." records\">$txt</A>";
		else
			$l[$ct] = "$txt";
		$cur -= ($result_group_size * ($ct+1) * 2);
	}
	/* Construct RIGHT link buttons */
	for ($ct = 0, $cur = $offset + $result_group_size; $ct < 4; $ct++)
	{
		$txt = str_repeat("&gt;", ($ct + 1));
		if ($cur <= $total - 1)
			$r[$ct] = "<A href=\"?$xtra&offset=$cur\" title=\"Forward ".($cur-$offset)." records\">$txt</A>";
		else
			$r[$ct] = "$txt";
		$cur += ($result_group_size * ($ct+1) * 2);
	}

	$colspan = ($rr_use_active ? 9 : 8);

?>
<TR>
	<TD colspan=<?php echo $colspan; ?> class=offsetbox>
		<TABLE class=offset width="100%">
			<TR>
				<TD align=left>
<?php
	echo $l[0] . " &nbsp; ";
	echo $l[1] . " &nbsp; ";
	echo $l[2] . " &nbsp; ";
	echo $l[3] . " &nbsp; ";
?>
				</TD>
				<TD align=center class=centeroffset>
<?php
	if (($top = $offset + $result_group_size) > $total)
		$top = $total;
	echo "<A href=\"?$xtra&offset=0\" title=\"Beginning of result\">&lt;|</A>";
	echo " &nbsp; ";
	echo nf($offset+1)."-".nf($top)." of ".nf($total);
	echo " &nbsp; ";
	echo "<A href=\"?$xtra&offset=" . ($total - $result_group_size) . "\" title=\"End of result\">|&gt;</A>";
?>
				</TD>
				<TD align=right>
<?php
	echo $r[3] . " &nbsp; ";
	echo $r[2] . " &nbsp; ";
	echo $r[1] . " &nbsp; ";
	echo $r[0] . " &nbsp; ";
?>
				</TD>
			</TR>
		</TABLE>
	</TD>
</TR>
<?php
}
/*--- output_offset_select() --------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	PTR_EDIT
	Assuming the query is in CIDR notation, edit PTR records.
	CIDR to range conversion by philippe-at-cyberabuse.org.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function ptr_edit($query)
{
	global $offset, $result_group_size, $ptr_use_active, $ptrtablename;

	$offset = (int)$offset;

	/* If this query is "in-addr.arpa", rewrite query */
	if (strstr($query, "in-addr.arpa"))
	{
		$nq = explode(".", $query);
		for ($query = "", $n = 3; $n >= 0; $n--)
			if (strspn($nq[$n], "0123456789.") == strlen($nq[$n]))
				$query .= ($query != "" ? "." : "") . "$nq[$n]";
	}

	/* If partial IP specified, replacing missing segments and get range */
	$quad = explode(".", $query);
	if (!$quad[1]) $quad[1] = "x";
	if (!$quad[2]) $quad[2] = "x";
	if (!$quad[3]) $quad[3] = "x";
	$mask = "$quad[0].$quad[1].$quad[2].$quad[3]";
	$low = str_replace("x", "0", $mask);
	$high = str_replace("x", "255", $mask);

	/* See if this block has a SOA record - if so, load the SOA record and output the form */
	if ($quad[2] != 'x') $soaname = "$quad[2].$quad[1].$quad[0].in-addr.arpa.";
	else if ($quad[1] != 'x') $soaname = "$quad[1].$quad[0].in-addr.arpa.";
	else $soaname = "$quad[0].in-addr.arpa.";
	if ($soa = load_soa($soaname))
	{
		soa_form($soa);
		/* If it has a SOA record, it may have resource records as well */
		top_level_rr_edit_form($soa);
	}

	$where = "WHERE ip >= " . ip2long($low) . " AND ip <= " . ip2long($high);

	$total = sql_count("SELECT COUNT(*) FROM $ptrtablename $where", "IP addresses in range");

	$fields = "id,ip,name,ttl";
	if ($ptr_use_active)
		$fields .= ",active+0 AS active_num";

	$where .= " ORDER BY ip";

	$q = "SELECT $fields FROM $ptrtablename $where";
	if ($result_group_size > 0)
		$q .= " LIMIT $offset,$result_group_size";
	$res = sql_query($q) or fatalSQL("Error loading PTR records");

	open_table("ptr");
	output_offset_select($offset, $total);
	while ($ptr = sql_fetch_array($res))
		ptrform($ptr);
/* Code patched by David Phillips <david@acz.org> */
	if ($total > 0)
		ptrform();
	close_table();
	if ($total == 0)
		fatal("Unable to find any records matching your query.");
/* End of patched code */
}
/*--- ptr_edit() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	TOP_LEVEL_RR_EDIT_FORM
	Outputs the form containing primary zone data (i.e. rr's with blank names or `*').
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function top_level_rr_edit_form($soa)
{
	global $rr_use_active, $rrtablename;

	open_table("rr");
	$fields = "*";
	if ($rr_use_active)
		$fields .= ",active+0 AS active_num";
	$q = "SELECT $fields FROM $rrtablename WHERE zone=$soa[id]".
		  " AND (name='' OR name='$soa[origin]') ORDER BY name,type";
	$res = sql_query($q)
		or fatalSQL("Error loading primary resource records for &quot;$soa[origin]&quot; zone.");
	while ($rr = sql_fetch_array($res))
		rrform($soa, $rr);
	rrform($soa);
	close_table();
}
/*--- top_level_rr_edit_form() ------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	ZONE_RR_EDIT_FORM
	Outputs a list of resource records (but not top level rescords) to edit.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function zone_rr_edit_form($soa, $host = NULL)
{
	global $offset, $result_group_size, $rr_use_active, $rrtablename;

	$offset = (int)$offset;

	if (!strlen($host))
		$where = "WHERE zone=$soa[id] AND name != '' AND name != '$soa[origin]'";
	else
		$where = "WHERE zone=$soa[id] AND name = '".esc($host)."'";

	$total = sql_count("SELECT COUNT(*) FROM $rrtablename $where", "RRs in zone $soa[id]");

	$fields = "*";
	if ($rr_use_active)
		$fields .= ",active+0 AS active_num";

	if (!strlen($host))
		$where = "WHERE zone=$soa[id] AND name != '' AND name != '$soa[origin]' ORDER BY name,type";
	else
		$where = "WHERE zone=$soa[id] AND name = '".esc($host)."' ORDER BY name,type";

	$q = "SELECT $fields FROM $rrtablename $where";
	if ($result_group_size > 0)
		$q .= " LIMIT $offset,$result_group_size";
	$res = sql_query($q)
			or fatalSQL("Error loading resource records for &quot;$host.$soa[origin]&quot;");

	open_table("rr", "Resource records");

	if (sql_num_rows($res))
	{
		output_offset_select($offset, $total);
		while ($rr = sql_fetch_array($res))
			rrform($soa, $rr);
	}

	rrform($soa);
	close_table();
}
/*--- zone_rr_edit_form() -----------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SHOW_FORM
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function show_form($query)
{
	global $host;

	if (!strlen($query))
	{
		output_help();
		return;
	}

	/* Edit PTR records if the query looks like numbers-and-dots */
	if (strlen($query) && strspn($query, "0123456789.") == strlen($query) || strstr($query, "in-addr.arpa"))
	{
		ptr_edit($query);
		close_page();
	}
	else
	{
		$soa = load_soa($query) or fatal("Unable to find any records matching your query.");
		if (!strlen($host))
		{
			soa_form($soa);
			top_level_rr_edit_form($soa);
			zone_rr_edit_form($soa);
		}
	}
}
/*--- show_form() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CHECK_SOA_FORMDATA
	Returns 0 if everything is OK, -1 if not.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function check_soa_formdata($soa = NULL)
{
	global $soatablename;
	global $ttl_min, $refresh_min, $retry_min, $expire_min;

	/* Load SOA record for record being updated */
	if ((int)$_POST[soa])
	{
		$res = sql_query("SELECT * FROM $soatablename WHERE id=".(int)($_POST[soa]))
			or fatalSQL("Error loading soa {$_POST[soa]}.");
		$soa = sql_fetch_array($res) or fatal("Unable to find soa {$_POST[soa]}.");
		$soa[minimum] = (int)$_POST[minimum];
	}

	$fail = "<BR>SOA record not updated.";

	foreach ($_POST as $n => $v)
		$_POST[$n] = trim($v);

	foreach ($_POST as $n => $v)
	switch ($n)
	{
		case "origin":
			$v = $_POST[$n] = fixfqdn($v);
			if (!strlen($v)) return notice("Origin field empty.".$fail);
			if (strlen($v) > 78) return notice("Origin field too long.".$fail);
			break;

		case "ns":
			$v = $_POST[$n] = fixfqdn($v);
			if (!strlen($v)) return notice("Authoritative nameserver field empty.".$fail);
			if (strlen($v) > 255) return notice("Authoritative nameserver field too long.".$fail);
			break;

		case "mbox":
			$v = $_POST[$n] = fixfqdn($v);
			if (!strlen($v)) return notice("Administrative mailbox field empty.".$fail);
			if (strlen($v) > 255) return notice("Administrative mailbox field too long.".$fail);
			break;

		case "ttl":
			if ($v < $ttl_min)
				return notice("TTL unreasonably short.<BR>".
						 "The minimum allowable value is $ttl_min (".duration($ttl_min).").".$fail);
			if ($v < $soa[minimum])
			{
				$_POST[ttl] = $soa[minimum];
				notice("TTL raised to {$soa[minimum]} (".duration($soa[minimum]).") ".
						 "to comply with the minimum TTL for this zone.");
			}
			break;

		case "serial":
			if (!strlen($v))
				return notice("Serial field empty.".$fail);
			break;

		case "refresh":
			if ($v < $refresh_min)
				return notice("Refresh time unreasonably short.<BR>".
								  "The minimum allowable value is $refresh_min ".
								  "(".duration($refresh_min).").".$fail);
			break;

		case "retry":
			if ($v < $retry_min)
				return notice("Retry time unreasonably short.<BR>".
								  "The minimum allowable value is $retry_min ".
								  "(".duration($retry_min).").".$fail);
			break;

		case "expire":
			if ($v < $expire_min)
				return notice("Expiration time unreasonably short.<BR>".
								  "The minimum allowable value is $expire_min ".
								  "(".duration($expire_min).").".$fail);
			break;

		case "minimum":
			if ($v < $minimum_min)
				return notice("Minimum TTL unreasonably short.<BR>".
								  "The minimum allowable value is $ttl_min ".
								  "(".duration($ttl_min).").".$fail);
			break;
	}
	return (0);
}
/*--- check_soa_formdata() ----------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SOAUPDATE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function soaupdate()
{
	global $soa_use_active, $soa_use_xfer, $soatablename;

	if (check_soa_formdata() == -1)
		return;

	$q  = "UPDATE $soatablename SET ";
	$q .= "ns='" . esc($_POST["ns"]) . "'";
	$q .= ",mbox='" . esc($_POST["mbox"]) . "'";
	$q .= ",serial=" . (int)($_POST["serial"]);
	$q .= ",refresh=" . (int)($_POST["refresh"]);
	$q .= ",retry=" . (int)($_POST["retry"]);
	$q .= ",expire=" . (int)($_POST["expire"]);
	$q .= ",minimum=" . (int)($_POST["minimum"]);
	$q .= ",ttl=" . (int)($_POST["ttl"]);

	if ($soa_use_active)
	{
		if ($_POST["active"] == "Y")
			$q .= ",active=1";
		else
			$q .= ",active=2";
	}

	if ($soa_use_xfer)
		$q .= ",xfer='" . esc($_POST["xfer"]) . "'";

	$q .= " WHERE id=" . (int)($_POST["soa"]);

	sql_query($q) or fatalSQL("Error updating SOA.");
}
/*--- soaupdate() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SOA_DELETE
	Delete the current SOA and all records.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function soa_delete()
{
	global $query, $soatablename, $rrtablename;

	$id = (int)$_POST["soa"];
	if ($_POST["confirm"] != "Yes")
	{
		Notice("
<FONT color=red><B>WARNING!</B></FONT>
<P>
If you delete this zone you will also be deleting all associated resource records!
<P>
If you really want to do that, click the button below:
<P>
<FORM method=POST action='".$_SERVER['PHP_SELF']."'>
<INPUT type=hidden name=action value='soaupdate'>
<INPUT type=hidden name=query value='$query'>
<INPUT type=hidden name=soa value='$id'>
<INPUT type=hidden name=confirm value='Yes'>
<INPUT type=submit name='soaaction' value='Delete'>"
		);
		return;
	}

	$q  = "DELETE FROM $rrtablename WHERE zone=" . (int)$id;
	sql_query($q) or fatalSQL("Error deleting resource records for zone.");

	$q  = "DELETE FROM $soatablename WHERE id=" . (int)$id;
	sql_query($q) or fatalSQL("Error deleting zone.");

	$query = NULL;
	Notice("Zone deleted");
}
/*--- soa_delete() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	UPDATE_SERIAL
	Update serial number for the specified zone, if $auto_update_serial is set.	
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function update_serial($zone)
{
	global $auto_update_serial, $soatablename;

	if (!$auto_update_serial)
		return;

	/* Get current serial for zone */
	$serial = sql_count("SELECT serial FROM $soatablename WHERE id=$zone", "serial for zone $zone");
	if ($auto_update_serial == 1)
		$new = strftime("%Y%m%d%H", time());
	else
		$new = time();

	/* This could use improvement - YYYYMMDD only allows one update per day - yuk! */
	sql_query("UPDATE $soatablename SET serial=$new WHERE id=$zone");
}
/*--- update_serial() ---------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RR_DELETE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function rr_delete()
{
	global $rrtablename;

	$q  = "DELETE FROM $rrtablename WHERE id=" . (int)$_POST[rr];

	sql_query($q) or fatalSQL("Error deleting resource record.");

	update_serial($_POST["soa"]);
}
/*--- rr_delete() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CHECK_RR_FORMDATA
	Returns 0 if everything is OK, -1 if not.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function check_rr_formdata($desc = "updated")
{
	global $soatablename;
	global $ttl_min;

	/* Load SOA record for record being updated */
	$res = sql_query("SELECT * FROM $soatablename WHERE id=".(int)($_POST[soa]))
		or fatalSQL("Error loading soa {$_POST[soa]}.");
	$soa = sql_fetch_array($res) or fatal("Unable to find soa {$_POST[soa]}.");

	$fail = "<BR>Resource record not $desc.";

	foreach ($_POST as $n => $v)
		$_POST[$n] = trim($v);

	foreach ($_POST as $n => $v)
	switch ($n)
	{
		case "name":
			if ($v == $soa[origin] || "$v." == $soa[origin])
				$v = $_POST[name] = "";
			while ($v[strlen($v)-1] == '.')
				$v = $_POST[name] = substr($v, 0, strlen($v)-1);
			if (strlen($v) > 64) return notice("Name field too long.".$fail);
			break;

		case "ttl":
			if ($v < $soa[minimum])
			{
				$v = $_POST[ttl] = $soa[minimum];
				notice("TTL raised to {$soa[minimum]} (".duration($soa[minimum]).") ".
						 "to comply with the minimum TTL for this zone.");
			}
			if ($v < $ttl_min)
				return notice("TTL unreasonably short.<BR>".
						 "The minimum allowable value is $ttl_min (".duration($ttl_min).").".$fail);
			break;

		case "type":		/* Do special processing on `data' for certain types */
			switch ($v)
			{
				case "A":
					/* XXX: Validate IPv4 address */
					break;

				case "AAAA":
					/* XXX: Validate IPv6 address */
					break;

				case "CNAME":
					$_POST[data] = fixfqdn($_POST[data]);
					$_POST[aux] = 0;
					break;

				case "MX":
					$_POST[data] = fixfqdn($_POST[data]);
					if ($_POST[aux] <= 0)
						$_POST[aux] = 1;
					break;

				case "NS":
					$_POST[data] = fixfqdn($_POST[data]);
					$_POST[aux] = 0;
					break;

				default:		/* "aux" is only used with MX records */
					$_POST[aux] = 0;
					break;
			}
			break;

		case "data":
			if (!strlen($v)) return notice("Data field empty.".$fail);
			if (strlen($v) > 255) return notice("Data field too long.".$fail);
			break;
	}
	return (0);
}
/*--- check_rr_formdata() -----------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RRUPDATE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function rrupdate()
{
	global $rr_use_active, $rrtablename;

	if (check_rr_formdata("updated") == -1)
		return;

	$q  = "UPDATE $rrtablename SET ";
	$q .= "name='" . esc($_POST["name"]) . "'";
	$q .= ",type='" . esc($_POST["type"]) . "'";
	$q .= ",data='" . esc($_POST["data"]) . "'";
	$q .= ",aux=" . (int)($_POST["aux"]);
	$q .= ",ttl=" . (int)($_POST["ttl"]);
	if ($rr_use_active)
	{
		if ($_POST["active"] == "Y")
			$q .= ",active=1";
		else
			$q .= ",active=2";
	}
	$q .= " WHERE id=" . (int)($_POST["rr"]);

	sql_query($q) or fatalSQL("Error updating resource record.");

	update_serial($_POST["soa"]);
}
/*--- rrupdate() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RRINSERT
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function rrinsert()
{
	global $rrtablename;

	if (check_rr_formdata("created") == -1)
		return;

	$q  = "INSERT INTO $rrtablename SET ";
	$q .= "zone=" . (int)($_POST["soa"]);
	$q .= ",name='" . esc($_POST["name"]) . "'";
	$q .= ",type='" . esc($_POST["type"]) . "'";
	$q .= ",data='" . esc($_POST["data"]) . "'";
	$q .= ",aux=" . (int)($_POST["aux"]);
	$q .= ",ttl=" . (int)($_POST["ttl"]);

	sql_query($q) or fatalSQL("Error creating resource record.");

	update_serial($_POST["soa"]);
}
/*--- rrinsert() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CHECK_PTR_FORMDATA
	Returns 0 if everything is OK, -1 if not.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function check_ptr_formdata($desc = "updated")
{
	foreach ($_POST as $n => $v)
		$_POST[$n] = trim($v);

	$fail = "<BR>PTR record not $desc.";

	$dd = $_POST[dd];
	$quad = explode(".", $dd);
	if ((int)$quad[0] < 0 || (int)$quad[0] > 255) return notice("IP address out of range.".$fail);
	if ((int)$quad[1] < 0 || (int)$quad[1] > 255) return notice("IP address out of range.".$fail);
	if ((int)$quad[2] < 0 || (int)$quad[2] > 255) return notice("IP address out of range.".$fail);
	if ((int)$quad[3] < 0 || (int)$quad[3] > 255) return notice("IP address out of range.".$fail);

	$_POST[name] = fixfqdn($_POST[name]);
	if (!strlen($_POST[name])) return notice("Name field empty.".$fail);
	if (strlen($_POST[name]) > 255) return notice("Name field too long.".$fail);

	return (0);
}
/*--- check_ptr_formdata() ----------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	PTRUPDATE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function ptrupdate()
{
	global $ptr_use_active, $ptrtablename;

	if (check_ptr_formdata("updated") == -1)
		return;

	$q  = "UPDATE $ptrtablename SET ";
	$q .= "name='" . esc($_POST["name"]) . "'";
	if ($ptr_use_active)
		$q .= ",active=" . ($_POST["active"] ? "1" : "2");
	$q .= " WHERE id=" . (int)($_POST["ptr"]);

	sql_query($q) or fatalSQL("Error updating PTR record.");
}
/*--- ptrupdate() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	PTR_DELETE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function ptr_delete()
{
	global $ptrtablename;

	$q  = "DELETE FROM $ptrtablename WHERE id=" . (int)$_POST[ptr];

	sql_query($q) or fatalSQL("Error deleting PTR record.");
}
/*--- ptr_delete() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	PTRINSERT
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function ptrinsert()
{
	global $ptrtablename;

	if (check_ptr_formdata("created") == -1)
		return;

	$q  = "INSERT INTO $ptrtablename SET ";
	$q .= "ip=INET_ATON('" . esc($_POST["dd"]) . "')";
	$q .= ",name='" . esc($_POST["name"]) . "'";

	sql_query($q) or fatalSQL("Error creating PTR record.");
}
/*--- ptrinsert() -------------------------------------------------------------------------------*/

 
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQL_ISCOLUMN
	Checks for a column named $column in $table.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function sql_iscolumn($table, $column)
{
	global $use_pgsql;

	if ($use_pgsql)
	{
		if (sql_count("SELECT COUNT(*) FROM pg_class,pg_attribute WHERE relkind='r'" .
			" AND relname='$table' AND attrelid=oid AND attname='$column'", "columns from table") > 0)
			return (1);
		return (0);
	}
	else
		return sql_count("SHOW COLUMNS FROM $table LIKE '$column'", "columns from table");
}
/*--- sql_iscolumn() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CHECK_OPTIONAL_COLUMNS
	Checks for the optional 'active' column in soa and rr tables.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function check_optional_columns()
{
	global $soa_use_active, $rr_use_active, $ptr_use_active;
	global $soa_use_xfer;
	global $soatablename, $rrtablename, $ptrtablename;

	$soa_use_active = sql_iscolumn($soatablename, "active");
	$soa_use_xfer = sql_iscolumn($soatablename, "xfer");
	$rr_use_active = sql_iscolumn($rrtablename, "active");
	$ptr_use_active = sql_iscolumn($ptrtablename, "active");
}
/*--- check_optional_columns() ------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SOA_BROWSER
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function soa_browser()
{
	global $offset, $soatablename, $rrtablename, $result_group_size;

	if (!strlen($offset))
		$offset = 0;

	$total = sql_count("SELECT COUNT(*) FROM $soatablename", "total number of zones");

	if (!$total)
	{
		notice("No zones in database");
		show_form("");
		return;
	}

	$q = "SELECT * FROM $soatablename ORDER BY origin";
	if ($result_group_size > 0)
		$q .= " LIMIT $offset,$result_group_size";

	$soa_res = sql_query($q) or fatalSQL("Error retrieving SOA records.<BR>$q");

	open_table("soa_browser", NULL, "100%");

	$bgcolor = "#FFFFCC";
	if (sql_num_rows($soa_res))
	{
		output_offset_select($offset, $total, "action=soa_browser");
		while ($soa = sql_fetch_array($soa_res))
		{
			$rrs = sql_count("SELECT COUNT(*) FROM $rrtablename WHERE zone=$soa[id]",
								  "resource records in zone $soa[id]");

			$bgcolor = ($bgcolor == "#FFFFCC" ? "#FFFFAA" : "#FFFFCC");

			echo "<TR bgcolor='$bgcolor'>";
			echo "<TD width='99%'>".
				  "<A href='?query=$soa[origin]' title='Click here to view/edit this zone'>".
				  "$soa[origin]</A></TD>";
			echo "<TD align=right>".nf($rrs)."&nbsp;record".($rrs==1?"&nbsp;":"s");
			echo "</TR>\n";
		}
	}
	close_table();
}
/*--- soa_browser() -----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	PTR_BROWSER
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function ptr_browser()
{
	global $offset, $soatablename, $ptrtablename, $result_group_size;

	if (!strlen($offset))
		$offset = 0;

	open_table("ptr");
	ptrform();
	close_table();

	$total = sql_count("SELECT COUNT(*) FROM $ptrtablename", "total number of PTR entries");

	if (!$total)
		return;

	$fields = "id,ip,name,ttl";
	if ($ptr_use_active)
		$fields .= ",active+0 AS active_num";

	$q = "SELECT $fields FROM $ptrtablename ORDER BY ip";
	if ($result_group_size > 0)
		$q .= " LIMIT $offset,$result_group_size";
	$ptr_res = sql_query($q) or fatalSQL("Error loading PTR records");

	open_table("ptr_browser", NULL);

	$bgcolor = "#FFFFCC";
	if (sql_num_rows($ptr_res))
	{
		output_offset_select($offset, $total, "action=ptr_browser");
		while ($ptr = sql_fetch_array($ptr_res))
			ptrform($ptr);
	}
	close_table();
}
/*--- ptr_browser() -----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SOA_ADD
	Form to add a new SOA record.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function soa_add()
{
	global $soatablename, $query, $soa_use_active, $soa_use_xfer;
	global $default_ttl, $default_refresh, $default_retry, $default_expire, $default_minimum;

	if ($_POST[soaaction] != "Create new SOA")
	{
		$soa[ttl] = $default_ttl;
		$soa[refresh] = $default_refresh;
		$soa[retry] = $default_retry;
		$soa[expire] = $default_expire;
		$soa[minimum] = $default_minimum;
		$soa[serial] = strftime("%Y%m%d", time());
		$soa[active] = "Y";
		$soa[active_num] = 1;
		soa_form($soa, 1);
		return;
	}

	$soa[origin] = fixfqdn($_POST[origin]);
	$soa[ns] = fixfqdn($_POST[ns]);
	$soa[mbox] = fixfqdn($_POST[mbox]);
	$soa[ttl] = $_POST[ttl];
	$soa[refresh] = $_POST[refresh];
	$soa[retry] = $_POST[retry];
	$soa[expire] = $_POST[expire];
	$soa[minimum] = $_POST[minimum];
	$soa[serial] = $_POST[serial];
	$soa[active] = $_POST[active];
	$soa[xfer] = $_POST[xfer];

	if (check_soa_formdata($soa) == -1)
	{
		soa_form($soa, 1);
		return;
	}

	if (sql_count("SELECT COUNT(*) FROM $soatablename WHERE origin='".esc($soa[origin])."'",
					  "zones with origin '$soa[origin]'"))
	{
		notice("Origin &quot;$soa[origin]&quot; already exists.<BR>Current origin displayed.");
		$query = $soa[origin];
		show_form($query);
		close_page();
		exit;
	}

	$q  = "INSERT INTO $soatablename SET ";
	$q .= "origin='".esc($soa[origin])."'";
	$q .= ",ns='".esc($soa[ns])."'";
	$q .= ",mbox='".esc($soa[mbox])."'";
	$q .= ",serial=".esc($soa[serial]);
	$q .= ",refresh=".esc($soa[refresh]);
	$q .= ",retry=".esc($soa[retry]);
	$q .= ",expire=".esc($soa[expire]);
	$q .= ",minimum=".esc($soa[minimum]);
	$q .= ",ttl=".esc($soa[ttl]);
	if ($soa_use_active)
	{
		if ($_POST["active"] == "Y")
			$q .= ",active=1";
		else
			$q .= ",active=2";
	}
	if ($soa_use_xfer)
		$q .= ",xfer='".esc($soa[xfer])."'";

	sql_query($q) or fatalSQL("Error inserting SOA record.");

	$query = $soa[origin];
	show_form($query);
	close_page();
	exit;
}
/*--- soa_add() ---------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	MAIN
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/* Output image data if requested */
if ($imgname = $_GET["img"])
	send_img($imgname);

if (isset($_GET['action'])) {
	$action = $_GET['action'];
} else if (isset($_POST['action'])) {
	$action = $_POST['action'];
}

if (isset($_GET['query'])) {
	$query = $_GET['query'];
} else if (isset($_POST['query'])) {
	$query = $_POST['query'];
}

if (isset($_GET['offset']))
	$offset = $_GET['offset'];

open_page();

if ($use_pgsql)
{
	pg_connect("host=$dbhost user=$dbuser password=$dbpass dbname=$dbname")
		or fatalSQL("Unable to connect to database.");
}
else
{
	mysql_connect($dbhost, $dbuser, $dbpass) or fatalSQL("Unable to connect to database.");
	mysql_select_db($dbname) or fatalSQL("Unable to select database.");
}

check_optional_columns();

$query = trim($query);

switch ($action)
{
	case "soaupdate":
		if ($_POST['soaaction'] == "Delete")
			soa_delete();
		else if ($_POST['soaaction'] == "Update")
			soaupdate();
		break;

	case "rrupdate":
		if ($_POST['rraction'] == "Delete")
			rr_delete();
		else if ($_POST['rraction'] == "Update")
			rrupdate();
		break;

	case "rrinsert":
		rrinsert();
		break;

	case "ptrupdate":
		if ($_POST['ptraction'] == "Delete")
			ptr_delete();
		else if ($_POST['ptraction'] == "Update")
			ptrupdate();
		break;

	case "ptrinsert":
		ptrinsert();
/* Code patched by David Phillips <david@acz.org> */
		$ip = explode(".", $_POST["dd"]);
		$query = implode(".", array_slice($ip, 0, 3));
/* End of patched code */
		break;

	case "soa_browser":
		soa_browser();
		close_page();
		exit;

	case "soa_add":
		soa_add();
		close_page();
		exit;

	case "ptr_browser":
		ptr_browser();
		close_page();
		exit;

	default:
		if ($action)
			notice("Unknown action: &quot;$action&quot;");
		break;
}

show_form($query);
close_page();

/*-----------------------------------------------------------------------------------------------*/

/* vi:set ts=3: */ ?>

